package bll

import (
	"context"
	"fmt"
	"go-micro.dev/v4/client"
	"reflect"
	"unsafe"

	"manager/client/grpc"
	"manager/errors"
	SignalPo "manager/model/signal"
	"manager/utils"
	"proto/dto"
)

type signal struct {
}

var Signal = &signal{}

// SendCmdToDevice 给设备端下发指令
func (s *signal) SendCmdToDevice(ctx context.Context, in *SignalPo.CommandReq) error {
	var (
		err error
	)

	//  查询sn码
	sn, err := Ebike.GetSn(in.EbikeId)
	if err != nil {
		return fmt.Errorf("get sn code failed")
	}

	cmd := &dto.CommandRequest{
		Sn:  sn,
		Cmd: dto.CmdType(in.Cmd),
	}

	fmt.Println("SendCmdToDevice  bikeId:", in.EbikeId, "data:", utils.ToJsonString(cmd))
	// 执行指令
	err = RpcCall(sn, func(addr string, err error) error {
		if err != nil {
			return err
		}

		_, err = grpc.Cmd.Command(ctx, cmd, func(options *client.CallOptions) {
			options.Address = []string{addr}
		})
		if err != nil {
			return fmt.Errorf("execute command failed")
		}
		return err
	})

	return nil
}

// SendToggleToDevice 给设备端下发指令
func (s *signal) SendToggleToDevice(ctx context.Context, in *SignalPo.ToggleReq) error {
	//  查询sn码
	sn, err := Ebike.GetSn(in.EbikeId)
	if err != nil {
		return fmt.Errorf("get sn code failed")
	}

	// 执行指令
	in.Sn = sn
	value := (*dto.SwitchRequest)(unsafe.Pointer(uintptr(unsafe.Pointer(in)) + uintptr(8)))

	fmt.Println("SendToggleToDevice  bikeId:", in.EbikeId, " data:", utils.ToJsonString(value))

	err = RpcCall(sn, func(addr string, err error) error {
		if err != nil {
			return err
		}

		_, err = grpc.Cmd.Switch(ctx, value, func(options *client.CallOptions) {
			options.Address = []string{addr}
		})
		if err != nil {
			return fmt.Errorf("execute switch command failed")
		}
		return err
	})

	return nil
}

// SendMsgToDevice 发送信息给设备端
func (s *signal) SendMsgToDevice(ctx context.Context, in *SignalPo.MessageReq) error {
	//  查询sn码
	sn, err := Ebike.GetSn(in.EbikeId)
	if err != nil {
		return fmt.Errorf("get sn code failed")
	}

	// 执行指令
	in.Sn = sn
	value := (*dto.SettingRequest)(unsafe.Pointer(uintptr(unsafe.Pointer(in)) + uintptr(8)))

	fmt.Println("SendMsgToDevice bikeId:", in.EbikeId, " data:", utils.ToJsonString(value))
	err = RpcCall(sn, func(addr string, err error) error {
		if err != nil {
			return err
		}

		_, err = grpc.Cmd.Setting(ctx, value, func(options *client.CallOptions) {
			options.Address = []string{addr}
		})
		if err != nil {
			return fmt.Errorf("execute Setting command failed")
		}
		return err
	})

	return nil
}

// GetMsgFromDevice 查询设备信息
func (s *signal) GetMsgFromDevice(ctx context.Context, in *SignalPo.GetMessageReq) (interface{}, error) {

	//  查询sn码
	sn, err := Ebike.GetSn(in.EbikeId)
	if err != nil {
		return nil, fmt.Errorf("get sn code failed")
	}

	rtype := reflect.TypeOf(grpc.Cmd)
	rvalue := reflect.ValueOf(grpc.Cmd)
	for i := 0; i < rvalue.NumMethod(); i++ {
		name := rtype.Method(i).Name
		if name != in.Cmd {
			continue
		}

		// 执行指令
		params := []reflect.Value{reflect.ValueOf(ctx), reflect.ValueOf(&SignalPo.BaseSearchRequest{Sn: sn})}

		fmt.Println("SendMsgToDevice bikeId:", in.EbikeId, " sn:", sn)
		results := rvalue.Method(i).Call(params)
		if len(results) == 2 && results[1].Interface() == nil {
			return results[0].Interface(), nil
		}

		// 错误处理
		if results[1].Interface() != nil {
			return nil, results[1].Interface().(error)
		}
	}

	return nil, errors.New(fmt.Sprintf("not exist rpc handler name:%v", in.Cmd))
}

func (s *signal) ReactiveCmd(ctx context.Context, in *dto.ReactiveRequest) error {
	return RpcCall(in.Sn, func(addr string, err error) error {
		if err != nil {
			return err
		}

		_, err = grpc.Cmd.Reactive(ctx, in, func(options *client.CallOptions) {
			options.Address = []string{addr}
		})
		return err
	})
}
